/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS  
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). 
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.  
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR  
 * COPYRIGHT LAW IS PROHIBITED.
 * 
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND  
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE  
 * MAY BE CONSIDERED TO BE A CONTRACT,
 * THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED 
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 * 
 */
package com.lineage.server.model.item.action;

import static com.lineage.server.model.skill.L1SkillId.AWAKEN_ANTHARAS;
import static com.lineage.server.model.skill.L1SkillId.AWAKEN_FAFURION;
import static com.lineage.server.model.skill.L1SkillId.AWAKEN_VALAKAS;
import static com.lineage.server.model.skill.L1SkillId.DECAY_POTION;

import java.util.Arrays;
import java.util.Map;
import java.util.StringTokenizer;

import org.w3c.dom.Element;

import com.lineage.server.PacketCreate;
import com.lineage.server.model.L1Object;
import com.lineage.server.model.Instance.L1ItemInstance;
import com.lineage.server.model.Instance.L1PcInstance;
import com.lineage.server.model.item.L1Item;
import com.lineage.server.packetserver.S_ServerMessage;
import com.lineage.server.packetserver.S_SystemMessage;
import com.lineage.server.utils.IntRange;
import com.lineage.server.utils.collections.Maps;

/**
 * Class <code>L1ItemXmlAction</code> 抽象类:道具XML动作.
 * 
 * @author jrwz
 * @version 2012-6-20下午03:30:46
 * @see com.lineage.server.model.item.action
 * @since JDK1.7
 */
public abstract class L1ItemXmlAction implements L1ItemAction {

    /** 道具类型. */
    private String itemType;
    /** 道具编号集合. */
    private final int[] itemIds;
    /** 职业Class. */
    private final int[] classes;
    /** 等级限制. */
    private final IntRange level;
    /** 职业类型. */
    private static final Map<Character, Integer> CHAR_TYPES = Maps.newMap();

    static {
        CHAR_TYPES.put('P', 0);
        CHAR_TYPES.put('K', 1);
        CHAR_TYPES.put('E', 2);
        CHAR_TYPES.put('W', 3);
        CHAR_TYPES.put('D', 4);
        CHAR_TYPES.put('R', 5);
        CHAR_TYPES.put('I', 6);
    }

    /**
     * 抽象类:道具XML动作.
     * 
     * @param element
     *            - XML 文档中的一个元素
     */
    public L1ItemXmlAction(final Element element) {
        this.itemType = element.getAttribute("类型");
        this.itemType = this.itemType.equals("") ? null : this.itemType;
        this.itemIds = this.parseItemIds(element.getAttribute("道具编号"));
        this.classes = this.parseClasses(element);
        this.level = this.parseLevel(element);
    }

    /**
     * 可接受职业类型.
     * 
     * @param type
     *            - 职业类型
     * @return 有此职业返回true
     */
    private boolean acceptsCharType(final int type) {
        if (0 < this.classes.length) {
            if (Arrays.binarySearch(this.classes, type) < 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * 可接受道具编号.
     * 
     * @param obj
     *            道具对象
     * @return true or false
     */
    private boolean acceptsItemId(final L1Object obj) {
        if (0 < this.itemIds.length) {
            if (!(obj instanceof L1ItemInstance)) {
                return false;
            }
            final int itemId = ((L1ItemInstance) obj).getItem().getItemId();
            if (Arrays.binarySearch(this.itemIds, itemId) < 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * 可接受等级.
     * 
     * @param i
     *            - 等级
     * @return 等级
     */
    private boolean acceptsLevel(final int i) {
        return this.level.includes(i);
    }

    @Override
    public boolean acceptsRequest(final L1PcInstance pc,
            final L1ItemInstance item) {
        if (!this.acceptsItemId(item)) {
            return false;
        }
        if (!this.acceptsLevel(pc.getLevel())) {
            return false;
        }
        if (!this.acceptsCharType(pc.getType())) {
            pc.sendPackets(new S_SystemMessage("\\f1你的职业无法使用此物品。"));
            return false;
        }
        if (!this.acceptsUseType(pc)) {
            return false;
        }
        return true;
    }

    /**
     * 可接受使用类型.
     * 
     * @param pc
     *            - 对象
     * @return True:可用、False:不可用
     */
    private boolean acceptsUseType(final L1PcInstance pc) {
        if (this.itemType == null) {
            return true;
        }
        if (this.itemType.equalsIgnoreCase("药水")) {
            // 法师魔法 (药水霜化术)
            if (pc.hasSkillEffect(DECAY_POTION)) {
                pc.sendPackets(new S_ServerMessage(698)); // 喉咙灼热，无法喝东西。
                return false;
            }
        } else if (this.itemType.equalsIgnoreCase("变身")) {
            // 不能变身的状态
            // 取回觉醒技能ID
            final int awakeSkillId = pc.getAwakeSkillId();
            if ((awakeSkillId == AWAKEN_ANTHARAS)
                    || (awakeSkillId == AWAKEN_FAFURION)
                    || (awakeSkillId == AWAKEN_VALAKAS)) {
                PacketCreate.get().sendSinglePackets(pc, "目前状态中无法变身");
                return false;
            }
        }
        return true;
    }

    @Override
    public abstract L1Item execute(final L1PcInstance pc,
            final L1ItemInstance useItem, final int readC1, final int readC2,
            final int targetId, final int targetX, final int targetY);

    @Override
    public L1Item executeWithAmount(final String actionName,
            final L1PcInstance pc, final L1ItemInstance item, final int amount) {
        return null;
    }

    /**
     * 解析职业Class.
     * 
     * @param element
     *            - XML 文档中的一个元素
     * @return 结果
     */
    private int[] parseClasses(final Element element) {
        final String classe = element.getAttribute("可用职业").toUpperCase();
        final int[] result = new int[classe.length()];
        int idx = 0;
        for (final Character cha : classe.toCharArray()) {
            result[idx++] = CHAR_TYPES.get(cha);
        }
        Arrays.sort(result);
        return result;
    }

    /**
     * 解析道具编号集合.
     * 
     * @param ids
     *            集合内的道具编号名称
     * @return 结果
     */
    private int[] parseItemIds(final String ids) {
        final StringTokenizer tok = new StringTokenizer(ids.replace(" ", ""),
                ",");
        final int[] result = new int[tok.countTokens()];
        for (int i = 0; i < result.length; i++) {
            result[i] = Integer.parseInt(tok.nextToken());
        }
        Arrays.sort(result);
        return result;
    }

    /**
     * 解析等级.
     * 
     * @param element
     *            - XML 文档中的一个元素
     * @return 等级
     */
    private IntRange parseLevel(final Element element) {
        final int lv = L1ItemXmlParser.getIntAttribute(element, "等级", 0);
        final int min = L1ItemXmlParser.getIntAttribute(element, "最低等级", 1);
        final int max = L1ItemXmlParser.getIntAttribute(element, "最高等级", 110);
        return lv == 0 ? new IntRange(min, max) : new IntRange(lv, lv);
    }
}
